package com.adcc.loadsheet.monitor.entity;

import com.adcc.loadsheet.monitor.util.AlarmEnum;
import com.adcc.loadsheet.monitor.util.Constant;
import com.adcc.loadsheet.monitor.util.StringUtil;

import java.util.HashSet;
import java.util.Set;

public class DatabaseMonitor extends BaseEntity implements Cloneable{

    // 主IP
    private String masterIp;

    // 主进程比
    private double masterProcessUsage;

    // 主活跃进程数
    private int masterActiveProcess;

    // 主最大进程数
    private int masterMaxProcess;

    // 主磁盘使用率
    private double masterDiskUsage;

    // 主表空间使用率
    private double masterTablespaceUsage;

    // 主连接状态
    private MonitorStatus masterStatus = MonitorStatus.ABNORMAL;

    // 从IP
    private String slaveIp;

    // 从进程比
    private double slaveProcessUsage;

    // 从活跃进程数
    private int slaveActiveProcess;

    // 从最大进程数
    private int slaveMaxProcess;

    // 从磁盘使用率
    private double slaveDiskUsage;

    // 从表空间使用率
    private double slaveTablespaceUsage;

    // 从连接状态
    private MonitorStatus slaveStatus = MonitorStatus.ABNORMAL;

    // 数据库总状态
    private MonitorStatus status = MonitorStatus.ABNORMAL;

    // 异常状态码(0：正常，1：异常，2：告警)
    private String errorCode = "00";

    // 异常原因：XXX IS DOWN,XXX IS DOWN
    private String errorReason = "";

    // 本模块异常的节点
    private Set<String> alarmContent = new HashSet<>();

    // 本模块正常的节点（用于判断告警确认后，部分节点正常后又异常需要重新告警）
    private Set<String> unAlarmContent = new HashSet<>();

    public String getMasterIp() {
        return masterIp;
    }

    public void setMasterIp(String masterIp) {
        this.masterIp = masterIp;
    }

    public double getMasterProcessUsage() {
        return masterProcessUsage;
    }

    public void setMasterProcessUsage(double masterProcessUsage) {
        this.masterProcessUsage = masterProcessUsage;
    }

    public int getMasterActiveProcess() {
        return masterActiveProcess;
    }

    public void setMasterActiveProcess(int masterActiveProcess) {
        this.masterActiveProcess = masterActiveProcess;
    }

    public int getMasterMaxProcess() {
        return masterMaxProcess;
    }

    public void setMasterMaxProcess(int masterMaxProcess) {
        this.masterMaxProcess = masterMaxProcess;
    }

    public double getMasterDiskUsage() {
        return masterDiskUsage;
    }

    public void setMasterDiskUsage(double masterDiskUsage) {
        this.masterDiskUsage = masterDiskUsage;
    }

    public double getMasterTablespaceUsage() {
        return masterTablespaceUsage;
    }

    public void setMasterTablespaceUsage(double masterTablespaceUsage) {
        this.masterTablespaceUsage = masterTablespaceUsage;
    }

    public MonitorStatus getMasterStatus() {
        return masterStatus;
    }

    public void setMasterStatus(MonitorStatus masterStatus) {
        this.masterStatus = masterStatus;
    }

    public String getSlaveIp() {
        return slaveIp;
    }

    public void setSlaveIp(String slaveIp) {
        this.slaveIp = slaveIp;
    }

    public double getSlaveProcessUsage() {
        return slaveProcessUsage;
    }

    public void setSlaveProcessUsage(double slaveProcessUsage) {
        this.slaveProcessUsage = slaveProcessUsage;
    }

    public int getSlaveActiveProcess() {
        return slaveActiveProcess;
    }

    public void setSlaveActiveProcess(int slaveActiveProcess) {
        this.slaveActiveProcess = slaveActiveProcess;
    }

    public int getSlaveMaxProcess() {
        return slaveMaxProcess;
    }

    public void setSlaveMaxProcess(int slaveMaxProcess) {
        this.slaveMaxProcess = slaveMaxProcess;
    }

    public double getSlaveDiskUsage() {
        return slaveDiskUsage;
    }

    public void setSlaveDiskUsage(double slaveDiskUsage) {
        this.slaveDiskUsage = slaveDiskUsage;
    }

    public double getSlaveTablespaceUsage() {
        return slaveTablespaceUsage;
    }

    public void setSlaveTablespaceUsage(double slaveTablespaceUsage) {
        this.slaveTablespaceUsage = slaveTablespaceUsage;
    }

    public MonitorStatus getSlaveStatus() {
        return slaveStatus;
    }

    public void setSlaveStatus(MonitorStatus slaveStatus) {
        this.slaveStatus = slaveStatus;
    }

    public MonitorStatus getStatus() {
        return status;
    }

    public void setStatus(MonitorStatus status) {
        this.status = status;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorReason() {
        return errorReason;
    }

    public void setErrorReason(String errorReason) {
        this.errorReason = errorReason;
    }

    public Set<String> getAlarmContent() {
        return alarmContent;
    }

    public void setAlarmContent(Set<String> alarmContent) {
        this.alarmContent = alarmContent;
    }

    public Set<String> getUnAlarmContent() {
        return unAlarmContent;
    }

    public void setUnAlarmContent(Set<String> unAlarmContent) {
        this.unAlarmContent = unAlarmContent;
    }

    @Override
    public String toXML() throws Exception {
        return null;
    }

    @Override
    public String toJSON() throws Exception {
        return null;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        DatabaseMonitor db = new DatabaseMonitor();
        db.setMasterIp(masterIp);
        db.setMasterProcessUsage(masterProcessUsage);
        db.setMasterActiveProcess(masterActiveProcess);
        db.setMasterMaxProcess(masterMaxProcess);
        db.setMasterDiskUsage(masterDiskUsage);
        db.setMasterTablespaceUsage(masterTablespaceUsage);
        db.setMasterStatus(masterStatus);
        db.setSlaveIp(slaveIp);
        db.setSlaveProcessUsage(slaveProcessUsage);
        db.setSlaveActiveProcess(slaveActiveProcess);
        db.setSlaveMaxProcess(slaveMaxProcess);
        db.setSlaveDiskUsage(slaveDiskUsage);
        db.setSlaveTablespaceUsage(slaveTablespaceUsage);
        db.setSlaveStatus(slaveStatus);
        db.setStatus(status);
        db.setErrorCode(errorCode);
        db.setErrorReason(errorReason);
        db.setAlarmContent(alarmContent);
        db.setUnAlarmContent(unAlarmContent);
        return db;
    }

    /**
     * 异常状态码
     */
    public void buildErrorCode() {
        StringBuilder sb = new StringBuilder();
        char[] states = new char[2];
        states[0] = masterStatus == MonitorStatus.NORMAL ? '0' : masterStatus == MonitorStatus.ABNORMAL ? '1' : '2';
        states[1] = slaveStatus == MonitorStatus.NORMAL ? '0' : slaveStatus == MonitorStatus.ABNORMAL ? '1' : '2';
        for(char c : states){
            sb.append(c);
        }
        this.errorCode = sb.toString();

        // [2024-6-01：张丽娟：增加声音和弹窗告警的功能，系统支持对指定告警项进行声音和弹窗告警忽略的功能: 根据状态码获取正常节点和异常节点信息]
        // 本模块异常的节点
        Set<String> alarmContent = new HashSet<>();
        // 本模块正常的节点（用于判断告警确认后，部分节点正常后又异常需要重新告警）
        Set<String> unAlarmContent = new HashSet<>();
        // 保存到数据库的异常信息
        StringBuilder errorReasonBuilder = new StringBuilder();

        AlarmEnum enumMaster = AlarmEnum.DATABASE_MASTER;
        if (states[0] == '1') {
            errorReasonBuilder.append(String.format(Constant.LOG_DOWN, enumMaster.getMysqlLogName()));
            alarmContent.add(enumMaster.getItem());
        }else if(states[0] == '2'){
            errorReasonBuilder.append(String.format(Constant.LOG_WARN, enumMaster.getMysqlLogName()));
            alarmContent.add(enumMaster.getItem());
        }else{
            unAlarmContent.add(enumMaster.getItem());
        }

        AlarmEnum enumSlave = AlarmEnum.DATABASE_SLAVE;
        if (states[1] == '1') {
            errorReasonBuilder.append(String.format(Constant.LOG_DOWN, enumSlave.getMysqlLogName()));
            alarmContent.add(enumSlave.getItem());
        }else if(states[1] == '2'){
            errorReasonBuilder.append(String.format(Constant.LOG_WARN, enumSlave.getMysqlLogName()));
            alarmContent.add(enumSlave.getItem());
        }else{
            unAlarmContent.add(enumSlave.getItem());
        }

        this.alarmContent = alarmContent;
        this.unAlarmContent = unAlarmContent;
        this.errorReason = StringUtil.stringBuilderToString(errorReasonBuilder);
    }

    /**
     * 告警升级，需要重新告警，即由一般变严重
     * （告警降级不需要重新告警，即由严重到一般）
     */
    public static Set<String> getReAlarmContents(MonitorStatus lastMasterStatus, MonitorStatus lastSlaveStatus,
                                                 MonitorStatus curMasterStatus, MonitorStatus curSlaveStatus) {
        // 告警升级，需要重新告警，即由一般变严重（告警降级不需要重新告警，即由严重到一般）
        Set<String> reAlertContent = new HashSet<>();
        // 上一次为一般告警，本次为严重告警
        if(lastMasterStatus == MonitorStatus.WARNING && curMasterStatus == MonitorStatus.ABNORMAL){
            AlarmEnum enumMaster = AlarmEnum.DATABASE_MASTER;
            reAlertContent.add(enumMaster.getItem());
        }
        // 上一次为一般告警，本次为严重告警
        if(lastSlaveStatus == MonitorStatus.WARNING && curSlaveStatus == MonitorStatus.ABNORMAL){
            AlarmEnum enumSlave = AlarmEnum.DATABASE_SLAVE;
            reAlertContent.add(enumSlave.getItem());
        }
        return reAlertContent;
    }
}
